/*
 * AIEngine a new generation network intrusion detection system.
 *
 * Copyright (C) 2013-2023  Luis Campo Giralte
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 * Boston, MA  02110-1301, USA.
 *
 * Written by Luis Campo Giralte <luis.camp0.2009@gmail.com> 
 *
 */
#ifndef SRC_PROTOCOLS_ICMP_ICMPPROTOCOL_H_
#define SRC_PROTOCOLS_ICMP_ICMPPROTOCOL_H_

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "Protocol.h"
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#if defined(IS_DARWIN)
#define ICMP_INFO_REQUEST ICMP_IREQ
#define ICMP_INFO_REPLY ICMP_IREQREPLY
#define ICMP_ADDRESS ICMP_MASKREQ
#define ICMP_ADDRESSREPLY ICMP_MASKREPLY
#endif

namespace aiengine {

class ICMPProtocol: public Protocol {
public:
    	explicit ICMPProtocol();
    	virtual ~ICMPProtocol() {}

	static const uint16_t header_size = 8;

	uint16_t getId() const override { return IPPROTO_ICMP; }
	uint16_t getHeaderSize() const override { return header_size; }

	// Condition for say that a packet is icmp 
	bool check(const Packet &packet) override; 
	void processFlow(Flow *flow) override { /* No flow to manage */ } 
	bool processPacket(Packet &packet) override;

	void statistics(std::basic_ostream<char> &out, int level, int32_t limit) const override;
	void statistics(Json &out, int level) const override;

	void releaseCache() override {} // No need to free cache

        void setHeader(const uint8_t *raw_packet) override { 
       
#if defined(IS_FREEBSD) || defined(IS_OPENBSD) || defined(IS_DARWIN)
                header_ = reinterpret_cast <const icmp*> (raw_packet);
#else
                header_ = reinterpret_cast <const icmphdr*> (raw_packet);
#endif
        }

#if defined(IS_FREEBSD) || defined(IS_OPENBSD) || defined(IS_DARWIN)
        uint8_t getType() const { return header_->icmp_type; }
        uint8_t getCode() const { return header_->icmp_code; }
        uint16_t getIdentifier() const { return ntohs(header_->icmp_id); }
        uint16_t getSequence() const { return ntohs(header_->icmp_seq); }
#else
        uint8_t getType() const { return header_->type; }
        uint8_t getCode() const { return header_->code; }
        uint16_t getIdentifier() const { return ntohs(header_->un.echo.id); }
        uint16_t getSequence() const { return ntohs(header_->un.echo.sequence); }
#endif

	uint64_t getCurrentUseMemory() const override { return sizeof(ICMPProtocol); }
	uint64_t getAllocatedMemory() const override { return sizeof(ICMPProtocol); }
	uint64_t getTotalAllocatedMemory() const override { return sizeof(ICMPProtocol); }

        void setDynamicAllocatedMemory(bool value) override {}
        bool isDynamicAllocatedMemory() const override { return false; }

	CounterMap getCounters() const override; 
	void resetCounters() override;

private:
#if defined(IS_FREEBSD) || defined(IS_OPENBSD) || defined(IS_DARWIN)
	const icmp *header_ = nullptr;
#else
	const icmphdr *header_ = nullptr;
#endif 
        uint32_t total_echo_request_ = 0;
        uint32_t total_echo_replay_ = 0;
        uint32_t total_destination_unreachable_ = 0;
        uint32_t total_source_quench_ = 0; // Router with congestion
        uint32_t total_redirect_ = 0;
        uint32_t total_router_advertisment_ = 0;
        uint32_t total_router_solicitation_ = 0;
	uint32_t total_ttl_exceeded_ = 0;
        uint32_t total_timestamp_request_ = 0;
        uint32_t total_timestamp_replay_ = 0;
	uint32_t total_info_request_ = 0;
	uint32_t total_info_reply_ = 0;
	uint32_t total_address_ = 0;
	uint32_t total_address_reply_ = 0;
        uint32_t total_others_ = 0;
};

typedef std::shared_ptr<ICMPProtocol> ICMPProtocolPtr;

} // namespace aiengine

#endif  // SRC_PROTOCOLS_ICMP_ICMPPROTOCOL_H_
